package com.magold.time;

public class AccurateTime implements Comparable<AccurateTime> {
	private long minute;
	private int second;
	private int millisecond;
	
	public AccurateTime(int minute, int second, int millisecond) {
		setMinute(minute);
		setSecond(second);
		setMillisecond(millisecond);
		
		assertTrue(parseMilliseconds() >= 0, "minute value is too big.");
	}
	
	public AccurateTime(long totalMilliseconds) {
		setTo(totalMilliseconds);
	}
	
	public void setTo(long totalMilliseconds) {
		this.millisecond = (int) totalMilliseconds % 1000;
		this.second = (int) (totalMilliseconds / 1000 % 60);
		this.minute = totalMilliseconds / 1000 / 60;
	}
	
	public long getMinute() {
		return minute;
	}

	public void setMinute(long minute) {
		assertTrue(minute >= 0,
				"Illeagl minute value: " + minute + " which should be positive");
		
		this.minute = minute;
	}

	public int getSecond() {
		return second;
	}

	public void setSecond(int second) {
		assertTrue(second >= 0 && second <= 59,
				"Illeagl second value: " + second + " which should range 0-59");
	
		this.second = second;
	}
	
	public int getMillisecond() {
		return millisecond;
	}

	public void setMillisecond(int millisecond) {
		assertTrue(second >= 0 && second <= 999,
				"Illeagl second value: " + second + " which should range 0-999");
	
		this.millisecond= millisecond;
	}
		
	private void assertTrue(boolean bool, String reason) {
		if (bool != true)
			throw new IllegalArgumentException(reason);
	}
	
	public void gain(AccurateTime toAdd) {
		long ms = parseMilliseconds() + toAdd.parseMilliseconds();
		setTo(ms);
	}
	
	public void gain(long pMsToAdd) {
		long ms = parseMilliseconds() + pMsToAdd;
		setTo(ms);
	}
	
	public long parseMilliseconds() {
		return minute * 60 * 1000 + second * 1000 + millisecond;
	}
	
	public AccurateTime calculateDelta(AccurateTime pTime) {
		long mMs = parseMilliseconds();
		long pMs = pTime.parseMilliseconds();
		
		return new AccurateTime(Math.abs(mMs - pMs));
	}

	/**
	 * compare support.
	 * 
	 * @return  1 means this time is longer than another
	 * 		   -1 means this time is shorter than another
	 * 		    0 means this time equals another
	 */
	@Override
	public int compareTo(AccurateTime another) {
		long myMs = parseMilliseconds();
		long anotherMs = another.parseMilliseconds();
		
		return (myMs > anotherMs)
				? 1
				: (myMs < anotherMs ? -1 : 0);
	}
	
	public boolean isLonger(AccurateTime another) {
		return compareTo(another) == 1;
	}
	
	public boolean isShorter(AccurateTime another) {
		return compareTo(another) == -1;
	}
	
	@Override
	public boolean equals(Object o) {
		if (this == o) return true;
		if (o instanceof AccurateTime && compareTo((AccurateTime) o) == 0) return true;
		
		return false;
	}
	
	@Override
	public int hashCode() {
		return (int) (millisecond * 60 + second + minute * 60000);
	}
	
	@Override
	public String toString() {
		return String.format("%02d:%02d:%03d", minute, second, millisecond);
	}
	
	public String toSimpleString() {
		return String.format("%02d:%02d", minute, second);
	}
	
}
